import 'package:backend.core/core/domain/entities/api/app_store/api_app_store_purchased_item.dart';
import 'package:backend.core/core/domain/entities/api/google_play/api_google_play_purchased_item.dart';
import 'package:backend.core/core/domain/entities/api/web/api_web_purchased_item.dart';
import 'package:backend.core/core/domain/entities/app_store/app_store_purchased_subscription_info.dart';
import 'package:backend.core/core/domain/entities/app_store/app_store_transaction.dart';
import 'package:backend.core/core/domain/entities/app_store_user_to_user_link.dart';
import 'package:backend.core/core/domain/entities/devices_to_app_store_user_link.dart';
import 'package:backend.core/core/domain/entities/devices_to_google_play_user_link.dart';
import 'package:backend.core/core/domain/entities/google_play/google_play_one_time_purchased_item_info.dart';
import 'package:backend.core/core/domain/entities/google_play/google_play_one_time_purchased_item_transaction.dart';
import 'package:backend.core/core/domain/entities/google_play/google_play_purchase_item_type.dart';
import 'package:backend.core/core/domain/entities/google_play/google_play_purchased_item_info.dart';
import 'package:backend.core/core/domain/entities/google_play/google_play_purchased_subscription_info.dart';
import 'package:backend.core/core/domain/entities/google_play/google_play_purchased_subscription_transaction.dart';
import 'package:backend.core/core/domain/entities/google_play/google_play_transaction.dart';
import 'package:backend.core/core/domain/entities/google_play_user_to_user_link.dart';
import 'package:backend.core/core/domain/entities/web/web_one_time_purchase_item.dart';
import 'package:backend.core/core/domain/entities/web/web_purchase_item.dart';
import 'package:backend.core/core/domain/entities/web/web_purchased_subscription_info.dart';
import 'package:backend.core/core/domain/entities/web/web_purchased_subscription_transaction.dart';
import 'package:backend.core/core/domain/entities/web/web_subscription.dart';
import 'package:backend.core/core/domain/entities/web/web_transaction.dart';
import 'package:backend.core/core/domain/entities/web/yookassa/yookassa_payment_method.dart';
import 'package:backend.core/core/domain/entities/web/yookassa/yookassa_pending_order.dart';
import 'package:backend.core/core/domain/entities/web/yookassa/yookassa_purchased_subscription_info.dart';
import 'package:backend.core/core/domain/entities/web/yookassa/yookassa_transaction.dart';
import 'package:backend.core/core/domain/errors/failures.dart';
import 'package:backend.core/core/domain/repositories/app_store_purchased_subscription_info_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/app_store_transaction_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/app_store_user_to_user_link_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/devices_to_app_store_user_link_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/devices_to_google_play_user_link_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/google_play_purchased_item_info_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/google_play_transaction_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/google_play_user_to_user_link_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/web_payment_method_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/web_purchase_item_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/web_purchased_subscription_info_repository/repository.dart';
import 'package:backend.core/core/domain/repositories/web_transaction_repository/repository.dart';
import 'package:backend.core/core/domain/utils/either_extension.dart';
import 'package:backend.core/core/domain/utils/uuid_generator.dart';
import 'package:backend.core/logger/logger.dart';
import 'package:backend.purchases/domain/entities/app_store_api/app_store_api_purchased_subscription_renewal_info.dart';
import 'package:backend.purchases/domain/entities/app_store_api/app_store_api_transaction.dart';
import 'package:backend.purchases/domain/entities/google_play_api/google_play_api_purchased_item.dart';
import 'package:backend.purchases/domain/entities/google_play_api/google_play_api_purchased_item_identifier.dart';
import 'package:backend.purchases/domain/entities/google_play_api/google_play_api_revoked_purchased_item.dart';
import 'package:backend.purchases/domain/entities/yookassa_api/payments/yookassa_api_canceled_payment.dart';
import 'package:backend.purchases/domain/entities/yookassa_api/payments/yookassa_api_succeeded_payment.dart';
import 'package:backend.purchases/domain/helpers/api/app_store/create_api_app_store_purchased_items_from_internal_ones.dart';
import 'package:backend.purchases/domain/helpers/api/google_play/create_api_google_play_purchased_items_from_internal_ones.dart';
import 'package:backend.purchases/domain/helpers/api/web/create_api_web_purchased_items_from_internal_ones.dart';
import 'package:backend.purchases/domain/helpers/app_store/create_app_store_purchased_subscription_info_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/app_store/create_app_store_transaction_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/get_web_purchased_subscription_max_lapse_duration.dart';
import 'package:backend.purchases/domain/helpers/get_web_purchased_subscription_transaction_expiration_time_map.dart';
import 'package:backend.purchases/domain/helpers/google_play/create_google_play_one_time_purchased_item_info_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/google_play/create_google_play_one_time_purchased_item_transaction_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/google_play/create_google_play_purchased_subscription_info_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/google_play/create_google_play_purchased_subscription_transaction_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/google_play/get_google_play_purchase_item_type.dart';
import 'package:backend.purchases/domain/helpers/google_play/update_google_play_one_time_purchased_item_info_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/google_play/update_google_play_one_time_purchased_item_transaction_from_revoked_purchased_item.dart';
import 'package:backend.purchases/domain/helpers/google_play/update_google_play_purchased_subscription_info_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/google_play/update_google_play_purchased_subscription_transaction_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/google_play/update_google_play_purchased_subscription_transaction_from_revoked_purchased_item.dart';
import 'package:backend.purchases/domain/helpers/yookassa/create_yookassa_one_time_purchased_item_transaction_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/yookassa/create_yookassa_payment_method_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/yookassa/create_yookassa_purchased_subscription_transaction_from_api_one.dart';
import 'package:backend.purchases/domain/helpers/yookassa/update_yookassa_payment_method_from_api_one.dart';
import 'package:backend.purchases/domain/repositories/app_store_api_purchased_item_repository/repository.dart';
import 'package:backend.purchases/domain/repositories/google_play_api_purchased_item_repository/repository.dart';
import 'package:backend.purchases/domain/repositories/yookassa_api_payment_repository/repository.dart';
import 'package:backend.purchases/domain/repositories/yookassa_pending_order_repository/repository.dart';
import 'package:built_collection/built_collection.dart';
import 'package:dartz/dartz.dart';
import 'package:equatable/equatable.dart';

part 'failures.dart';

part 'result.dart';

abstract class RestorePurchasedItems {
  Future<Either<PurchasedItemRestorationFailure, PurchasedItemRestorationResult>> call({
    required String? userId,
    required String? deviceId,
    required BuiltList<GooglePlayApiPurchasedItemIdentifier>? googlePlayApiPurchasedItemIdentifiers,
    required String? appStoreReceipt,
  });
}

class RestorePurchasedItemsImpl implements RestorePurchasedItems {
  const RestorePurchasedItemsImpl({
    required AppStoreUserToUserLinkRepository appStoreUserToUserLinkRepository,
    required GooglePlayUserToUserLinkRepository googlePlayUserToUserLinkRepository,
    required DevicesToAppStoreUserLinkRepository devicesToAppStoreUserLinkRepository,
    required DevicesToGooglePlayUserLinkRepository devicesToGooglePlayUserLinkRepository,
    required AppStoreTransactionRepository appStoreTransactionRepository,
    required AppStorePurchasedSubscriptionInfoRepository
        appStorePurchasedSubscriptionInfoRepository,
    required GooglePlayPurchasedItemInfoRepository googlePlayPurchasedItemInfoRepository,
    required GooglePlayTransactionRepository googlePlayTransactionRepository,
    required AppStoreApiPurchasedItemRepository appStoreApiPurchasedItemRepository,
    required GooglePlayApiPurchasedItemRepository googlePlayApiPurchasedItemRepository,
    required YookassaPendingOrderRepository yookassaPendingOrderRepository,
    required YookassaApiPaymentRepository yookassaApiPaymentRepository,
    required WebPaymentMethodRepository webPaymentMethodRepository,
    required WebPurchaseItemRepository webPurchaseItemRepository,
    required WebTransactionRepository webTransactionRepository,
    required WebPurchasedSubscriptionInfoRepository webPurchasedSubscriptionInfoRepository,
    required GetGooglePlayPurchaseItemType getGooglePlayPurchaseItemType,
    required UpdateGooglePlayOneTimePurchasedItemInfoFromApiOne
        updateGooglePlayOneTimePurchasedItemInfoFromApiOne,
    required UpdateGooglePlayPurchasedSubscriptionInfoFromApiOne
        updateGooglePlayPurchasedSubscriptionInfoFromApiOne,
    required CreateGooglePlayOneTimePurchasedItemInfoFromApiOne
        createGooglePlayOneTimePurchasedItemInfoFromApiOne,
    required CreateGooglePlayPurchasedSubscriptionInfoFromApiOne
        createGooglePlayPurchasedSubscriptionInfoFromApiOne,
    required UpdateGooglePlayPurchasedSubscriptionTransactionFromApiOne
        updateGooglePlayPurchasedSubscriptionTransactionFromApiOne,
    required CreateGooglePlayOneTimePurchasedItemTransactionFromApiOne
        createGooglePlayOneTimePurchasedItemTransactionFromApiOne,
    required CreateGooglePlayPurchasedSubscriptionTransactionFromApiOne
        createGooglePlayPurchasedSubscriptionTransactionFromApiOne,
    required UpdateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem
        updateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem,
    required UpdateGooglePlayOneTimePurchasedItemTransactionFromRevokedPurchasedItem
        updateGooglePlayOneTimePurchasedItemTransactionFromRevokedPurchasedItem,
    required CreateAppStoreTransactionFromApiOne createAppStoreTransactionFromApiOne,
    required CreateAppStorePurchasedSubscriptionInfoFromApiOne
        createAppStorePurchasedSubscriptionInfoFromApiOne,
    required CreateYookassaPaymentMethodFromApiOne createYookassaPaymentMethodFromApiOne,
    required UpdateYookassaPaymentMethodFromApiOne updateYookassaPaymentMethodFromApiOne,
    required CreateYookassaOneTimePurchasedItemTransactionFromApiOne
        createYookassaOneTimePurchasedItemTransactionFromApiOne,
    required CreateYookassaPurchasedSubscriptionTransactionFromApiOne
        createYookassaPurchasedSubscriptionTransactionFromApiOne,
    required CreateApiAppStorePurchasedItemsFromInternalOnes
        createApiAppStorePurchasedItemsFromInternalOnes,
    required CreateApiGooglePlayPurchasedItemsFromInternalOnes
        createApiGooglePlayPurchasedItemsFromInternalOnes,
    required CreateApiWebPurchasedItemsFromInternalOnes createApiWebPurchasedItemsFromInternalOnes,
    required GetWebPurchasedSubscriptionTransactionExpirationTimeMap
        getWebPurchasedSubscriptionTransactionExpirationTimeMap,
    required GetWebPurchasedSubscriptionMaxLapseDuration
        getWebPurchasedSubscriptionMaxLapseDuration,
  })  : _appStoreUserToUserLinkRepository = appStoreUserToUserLinkRepository,
        _googlePlayUserToUserLinkRepository = googlePlayUserToUserLinkRepository,
        _devicesToAppStoreUserLinkRepository = devicesToAppStoreUserLinkRepository,
        _devicesToGooglePlayUserLinkRepository = devicesToGooglePlayUserLinkRepository,
        _appStoreTransactionRepository = appStoreTransactionRepository,
        _appStorePurchasedSubscriptionInfoRepository = appStorePurchasedSubscriptionInfoRepository,
        _googlePlayPurchasedItemInfoRepository = googlePlayPurchasedItemInfoRepository,
        _googlePlayTransactionRepository = googlePlayTransactionRepository,
        _appStoreApiPurchasedItemRepository = appStoreApiPurchasedItemRepository,
        _googlePlayApiPurchasedItemRepository = googlePlayApiPurchasedItemRepository,
        _yookassaPendingOrderRepository = yookassaPendingOrderRepository,
        _yookassaApiPaymentRepository = yookassaApiPaymentRepository,
        _webPaymentMethodRepository = webPaymentMethodRepository,
        _webPurchaseItemRepository = webPurchaseItemRepository,
        _webTransactionRepository = webTransactionRepository,
        _webPurchasedSubscriptionInfoRepository = webPurchasedSubscriptionInfoRepository,
        _getGooglePlayPurchaseItemType = getGooglePlayPurchaseItemType,
        _updateGooglePlayOneTimePurchasedItemInfoFromApiOne =
            updateGooglePlayOneTimePurchasedItemInfoFromApiOne,
        _updateGooglePlayPurchasedSubscriptionInfoFromApiOne =
            updateGooglePlayPurchasedSubscriptionInfoFromApiOne,
        _createGooglePlayOneTimePurchasedItemInfoFromApiOne =
            createGooglePlayOneTimePurchasedItemInfoFromApiOne,
        _createGooglePlayPurchasedSubscriptionInfoFromApiOne =
            createGooglePlayPurchasedSubscriptionInfoFromApiOne,
        _updateGooglePlayPurchasedSubscriptionTransactionFromApiOne =
            updateGooglePlayPurchasedSubscriptionTransactionFromApiOne,
        _createGooglePlayOneTimePurchasedItemTransactionFromApiOne =
            createGooglePlayOneTimePurchasedItemTransactionFromApiOne,
        _createGooglePlayPurchasedSubscriptionTransactionFromApiOne =
            createGooglePlayPurchasedSubscriptionTransactionFromApiOne,
        _updateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem =
            updateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem,
        _updateGooglePlayOneTimePurchasedItemTransactionFromRevokedPurchasedItem =
            updateGooglePlayOneTimePurchasedItemTransactionFromRevokedPurchasedItem,
        _createAppStoreTransactionFromApiOne = createAppStoreTransactionFromApiOne,
        _createAppStorePurchasedSubscriptionInfoFromApiOne =
            createAppStorePurchasedSubscriptionInfoFromApiOne,
        _createYookassaPaymentMethodFromApiOne = createYookassaPaymentMethodFromApiOne,
        _updateYookassaPaymentMethodFromApiOne = updateYookassaPaymentMethodFromApiOne,
        _createYookassaOneTimePurchasedItemTransactionFromApiOne =
            createYookassaOneTimePurchasedItemTransactionFromApiOne,
        _createYookassaPurchasedSubscriptionTransactionFromApiOne =
            createYookassaPurchasedSubscriptionTransactionFromApiOne,
        _createApiAppStorePurchasedItemsFromInternalOnes =
            createApiAppStorePurchasedItemsFromInternalOnes,
        _createApiGooglePlayPurchasedItemsFromInternalOnes =
            createApiGooglePlayPurchasedItemsFromInternalOnes,
        _createApiWebPurchasedItemsFromInternalOnes = createApiWebPurchasedItemsFromInternalOnes,
        _getWebPurchasedSubscriptionTransactionExpirationTimeMap =
            getWebPurchasedSubscriptionTransactionExpirationTimeMap,
        _getWebPurchasedSubscriptionMaxLapseDuration = getWebPurchasedSubscriptionMaxLapseDuration;

  final AppStoreUserToUserLinkRepository _appStoreUserToUserLinkRepository;
  final GooglePlayUserToUserLinkRepository _googlePlayUserToUserLinkRepository;
  final DevicesToAppStoreUserLinkRepository _devicesToAppStoreUserLinkRepository;
  final DevicesToGooglePlayUserLinkRepository _devicesToGooglePlayUserLinkRepository;
  final AppStoreTransactionRepository _appStoreTransactionRepository;
  final AppStorePurchasedSubscriptionInfoRepository _appStorePurchasedSubscriptionInfoRepository;
  final GooglePlayPurchasedItemInfoRepository _googlePlayPurchasedItemInfoRepository;
  final GooglePlayTransactionRepository _googlePlayTransactionRepository;
  final AppStoreApiPurchasedItemRepository _appStoreApiPurchasedItemRepository;
  final GooglePlayApiPurchasedItemRepository _googlePlayApiPurchasedItemRepository;
  final YookassaPendingOrderRepository _yookassaPendingOrderRepository;
  final YookassaApiPaymentRepository _yookassaApiPaymentRepository;
  final WebPaymentMethodRepository _webPaymentMethodRepository;
  final WebPurchaseItemRepository _webPurchaseItemRepository;
  final WebTransactionRepository _webTransactionRepository;
  final WebPurchasedSubscriptionInfoRepository _webPurchasedSubscriptionInfoRepository;

  final GetGooglePlayPurchaseItemType _getGooglePlayPurchaseItemType;
  final UpdateGooglePlayOneTimePurchasedItemInfoFromApiOne
      _updateGooglePlayOneTimePurchasedItemInfoFromApiOne;
  final UpdateGooglePlayPurchasedSubscriptionInfoFromApiOne
      _updateGooglePlayPurchasedSubscriptionInfoFromApiOne;
  final CreateGooglePlayOneTimePurchasedItemInfoFromApiOne
      _createGooglePlayOneTimePurchasedItemInfoFromApiOne;
  final CreateGooglePlayPurchasedSubscriptionInfoFromApiOne
      _createGooglePlayPurchasedSubscriptionInfoFromApiOne;
  final UpdateGooglePlayPurchasedSubscriptionTransactionFromApiOne
      _updateGooglePlayPurchasedSubscriptionTransactionFromApiOne;
  final CreateGooglePlayOneTimePurchasedItemTransactionFromApiOne
      _createGooglePlayOneTimePurchasedItemTransactionFromApiOne;
  final CreateGooglePlayPurchasedSubscriptionTransactionFromApiOne
      _createGooglePlayPurchasedSubscriptionTransactionFromApiOne;
  final UpdateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem
      _updateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem;
  final UpdateGooglePlayOneTimePurchasedItemTransactionFromRevokedPurchasedItem
      _updateGooglePlayOneTimePurchasedItemTransactionFromRevokedPurchasedItem;
  final CreateAppStoreTransactionFromApiOne _createAppStoreTransactionFromApiOne;
  final CreateAppStorePurchasedSubscriptionInfoFromApiOne
      _createAppStorePurchasedSubscriptionInfoFromApiOne;
  final CreateYookassaPaymentMethodFromApiOne _createYookassaPaymentMethodFromApiOne;
  final UpdateYookassaPaymentMethodFromApiOne _updateYookassaPaymentMethodFromApiOne;
  final CreateYookassaOneTimePurchasedItemTransactionFromApiOne
      _createYookassaOneTimePurchasedItemTransactionFromApiOne;
  final CreateYookassaPurchasedSubscriptionTransactionFromApiOne
      _createYookassaPurchasedSubscriptionTransactionFromApiOne;
  final CreateApiAppStorePurchasedItemsFromInternalOnes
      _createApiAppStorePurchasedItemsFromInternalOnes;
  final CreateApiGooglePlayPurchasedItemsFromInternalOnes
      _createApiGooglePlayPurchasedItemsFromInternalOnes;
  final CreateApiWebPurchasedItemsFromInternalOnes _createApiWebPurchasedItemsFromInternalOnes;
  final GetWebPurchasedSubscriptionTransactionExpirationTimeMap
      _getWebPurchasedSubscriptionTransactionExpirationTimeMap;
  final GetWebPurchasedSubscriptionMaxLapseDuration _getWebPurchasedSubscriptionMaxLapseDuration;

  @override
  Future<Either<PurchasedItemRestorationFailure, PurchasedItemRestorationResult>> call({
    required String? userId,
    required String? deviceId,
    required BuiltList<GooglePlayApiPurchasedItemIdentifier>? googlePlayApiPurchasedItemIdentifiers,
    required String? appStoreReceipt,
  }) async {
    String? linkedAppStoreUserId;
    String? linkedGooglePlayUserId;

    if (userId != null) {
      final futureResults = await Future.wait([
        _appStoreUserToUserLinkRepository.findLinkByUserId(
          userId: userId,
        ),
        _googlePlayUserToUserLinkRepository.findLinkByUserId(
          userId: userId,
        ),
      ]);

      var i = 0;
      final appStoreUserLink = futureResults[i++] as AppStoreUserToUserLink?;
      final googlePlayUserLink = futureResults[i++] as GooglePlayUserToUserLink?;

      linkedAppStoreUserId = appStoreUserLink?.appStoreUserId;
      linkedGooglePlayUserId = googlePlayUserLink?.googlePlayUserId;
    }

    // find updatable google play purchased item identifiers

    String? effectiveGooglePlayUserId;
    final effectiveGooglePlayApiPurchasedItemIdentifiers = <GooglePlayApiPurchasedItemIdentifier>{};

    var apiGooglePlayPurchasedItems = BuiltList<ApiGooglePlayPurchasedItem>();

    if (googlePlayApiPurchasedItemIdentifiers != null) {
      effectiveGooglePlayApiPurchasedItemIdentifiers.addAll(googlePlayApiPurchasedItemIdentifiers);

      final purchaseTokens = googlePlayApiPurchasedItemIdentifiers.map((purchasedItemIdentifier) {
        return purchasedItemIdentifier.purchaseToken;
      }).toBuiltList();

      final nullablePurchasedItemInfos =
          await _googlePlayPurchasedItemInfoRepository.findPurchasedItemInfosByTokens(
        purchaseTokens: purchaseTokens,
      );

      final purchasedItemInfos =
          nullablePurchasedItemInfos.whereType<GooglePlayPurchasedItemInfo>();

      if (purchasedItemInfos.isNotEmpty) {
        effectiveGooglePlayUserId = purchasedItemInfos.first.googlePlayUserId;

        final savedUserPurchasedItemInfos =
            await _googlePlayPurchasedItemInfoRepository.findUserPurchasedItemInfos(
          googlePlayUserId: effectiveGooglePlayUserId,
        );

        for (final purchasedItemInfo in savedUserPurchasedItemInfos) {
          final apiPurchasedItemIdentifier = GooglePlayApiPurchasedItemIdentifier(
            purchaseToken: purchasedItemInfo.purchaseToken,
            purchaseItemSku: purchasedItemInfo.purchaseItemSku,
          );

          effectiveGooglePlayApiPurchasedItemIdentifiers.add(apiPurchasedItemIdentifier);
        }
      }
    } else if (linkedGooglePlayUserId != null) {
      effectiveGooglePlayUserId = linkedGooglePlayUserId;

      final savedUserPurchasedItemInfos =
          await _googlePlayPurchasedItemInfoRepository.findUserPurchasedItemInfos(
        googlePlayUserId: linkedGooglePlayUserId,
      );

      for (final purchasedItemInfo in savedUserPurchasedItemInfos) {
        final apiPurchasedItemIdentifier = GooglePlayApiPurchasedItemIdentifier(
          purchaseToken: purchasedItemInfo.purchaseToken,
          purchaseItemSku: purchasedItemInfo.purchaseItemSku,
        );

        effectiveGooglePlayApiPurchasedItemIdentifiers.add(apiPurchasedItemIdentifier);
      }
    }

    // update google play purchased items

    if (effectiveGooglePlayApiPurchasedItemIdentifiers.isNotEmpty) {
      effectiveGooglePlayUserId ??= UuidGenerator().generateUuid();

      final failureOrRevokedPurchasedItems =
          await _googlePlayApiPurchasedItemRepository.getRevokedPurchasedItems();

      final revokedPurchasedItemMap = <String, GooglePlayApiRevokedPurchasedItem>{};

      if (failureOrRevokedPurchasedItems.isRight()) {
        final revokedPurchasedItems = failureOrRevokedPurchasedItems.asRight();

        for (final revokedPurchasedItem in revokedPurchasedItems) {
          revokedPurchasedItemMap[revokedPurchasedItem.purchaseToken] = revokedPurchasedItem;
        }
      }

      final updatedApiPurchasedItemMap = <String, GooglePlayApiPurchasedItem>{};

      for (final apiPurchasedItemIdentifier in effectiveGooglePlayApiPurchasedItemIdentifiers) {
        final failureOrPurchaseItemType = _getGooglePlayPurchaseItemType(
          purchaseItemSku: apiPurchasedItemIdentifier.purchaseItemSku,
        );

        if (failureOrPurchaseItemType.isLeft()) {
          Logger().e(
            'Unknown purchase item sku: ${apiPurchasedItemIdentifier.purchaseItemSku}',
            null,
            StackTrace.current,
          );

          continue;
        }

        final purchaseItemType = failureOrPurchaseItemType.asRight();

        if (purchaseItemType.isSubscription) {
          final failureOrApiPurchasedSubscription =
              await _googlePlayApiPurchasedItemRepository.getPurchasedSubscription(
            purchasedItemIdentifier: apiPurchasedItemIdentifier,
          );

          if (failureOrApiPurchasedSubscription.isRight()) {
            final updatedApiPurchasedSubscription = failureOrApiPurchasedSubscription.asRight();

            updatedApiPurchasedItemMap[apiPurchasedItemIdentifier.purchaseToken] =
                updatedApiPurchasedSubscription;
          }
        } else if (purchaseItemType.isOneTimePurchaseItem) {
          final failureOrApiOneTimePurchasedItem =
              await _googlePlayApiPurchasedItemRepository.getOneTimePurchasedItem(
            purchasedItemIdentifier: apiPurchasedItemIdentifier,
          );

          if (failureOrApiOneTimePurchasedItem.isRight()) {
            final updatedApiOneTimePurchasedItem = failureOrApiOneTimePurchasedItem.asRight();

            updatedApiPurchasedItemMap[apiPurchasedItemIdentifier.purchaseToken] =
                updatedApiOneTimePurchasedItem;
          }
        }
      }

      var futureResults = await Future.wait([
        _googlePlayPurchasedItemInfoRepository.findUserPurchasedItemInfos(
          googlePlayUserId: effectiveGooglePlayUserId,
        ),
        _googlePlayTransactionRepository.findUserTransactions(
          googlePlayUserId: effectiveGooglePlayUserId,
        ),
      ]);

      var i = 0;

      final savedUserPurchasedItemInfos =
          futureResults[i++] as BuiltList<GooglePlayPurchasedItemInfo>;
      final savedUserPurchasedItemTransactions =
          futureResults[i++] as BuiltList<GooglePlayTransaction>;

      final savedUserPurchasedItemInfoMap = <String, GooglePlayPurchasedItemInfo>{};

      for (final purchasedItemInfo in savedUserPurchasedItemInfos) {
        savedUserPurchasedItemInfoMap[purchasedItemInfo.purchaseToken] = purchasedItemInfo;
      }

      final savedUserPurchasedItemTransactionMap = <String, GooglePlayTransaction>{};

      for (final purchasedItemTransaction in savedUserPurchasedItemTransactions) {
        savedUserPurchasedItemTransactionMap[purchasedItemTransaction.orderId] =
            purchasedItemTransaction;
      }

      final updatedPurchasedItemInfos = <GooglePlayPurchasedItemInfo>[];
      final updatedPurchasedItemTransactions = <GooglePlayTransaction>[];

      for (final updatedApiPurchasedItemMapEntry in updatedApiPurchasedItemMap.entries) {
        final purchaseToken = updatedApiPurchasedItemMapEntry.key;
        final updatedApiPurchasedItem = updatedApiPurchasedItemMapEntry.value;
        final orderId = updatedApiPurchasedItem.orderId;

        final purchaseItemSku =
            effectiveGooglePlayApiPurchasedItemIdentifiers.firstWhere((apiPurchasedItemIdentifier) {
          return apiPurchasedItemIdentifier.purchaseToken == purchaseToken;
        }).purchaseItemSku;

        if (savedUserPurchasedItemInfoMap.containsKey(purchaseToken)) {
          final purchasedItemInfo = savedUserPurchasedItemInfoMap[purchaseToken]!;

          if (purchasedItemInfo is GooglePlayOneTimePurchasedItemInfo) {
            final oneTimePurchasedItemInfo = purchasedItemInfo;
            final updatedApiOneTimePurchasedItem =
                updatedApiPurchasedItem as GooglePlayApiOneTimePurchasedItem;

            final updatedOneTimePurchasedItemInfo =
                _updateGooglePlayOneTimePurchasedItemInfoFromApiOne(
              oneTimePurchasedItemInfo: oneTimePurchasedItemInfo,
              updatedApiOneTimePurchasedItem: updatedApiOneTimePurchasedItem,
            );

            updatedPurchasedItemInfos.add(updatedOneTimePurchasedItemInfo);
          } else if (purchasedItemInfo is GooglePlayPurchasedSubscriptionInfo) {
            final purchasedSubscriptionInfo = purchasedItemInfo;
            final updatedApiPurchasedSubscription =
                updatedApiPurchasedItem as GooglePlayApiPurchasedSubscription;

            final updatedPurchasedSubscriptionInfo =
                _updateGooglePlayPurchasedSubscriptionInfoFromApiOne(
              purchasedSubscriptionInfo: purchasedSubscriptionInfo,
              updatedApiPurchasedSubscription: updatedApiPurchasedSubscription,
            );

            updatedPurchasedItemInfos.add(updatedPurchasedSubscriptionInfo);
          }
        } else {
          if (updatedApiPurchasedItem is GooglePlayApiOneTimePurchasedItem) {
            final apiOneTimePurchasedItem = updatedApiPurchasedItem;

            final oneTimePurchasedItemInfo = _createGooglePlayOneTimePurchasedItemInfoFromApiOne(
              apiOneTimePurchasedItem: apiOneTimePurchasedItem,
              googlePlayUserId: effectiveGooglePlayUserId,
              purchaseToken: purchaseToken,
              purchaseItemSku: purchaseItemSku,
            );

            updatedPurchasedItemInfos.add(oneTimePurchasedItemInfo);
          } else if (updatedApiPurchasedItem is GooglePlayApiPurchasedSubscription) {
            final apiPurchasedSubscription = updatedApiPurchasedItem;

            final purchasedSubscriptionInfo = _createGooglePlayPurchasedSubscriptionInfoFromApiOne(
              apiPurchasedSubscription: apiPurchasedSubscription,
              googlePlayUserId: effectiveGooglePlayUserId,
              purchaseToken: purchaseToken,
              purchaseItemSku: purchaseItemSku,
            );

            updatedPurchasedItemInfos.add(purchasedSubscriptionInfo);
          }
        }

        if (savedUserPurchasedItemTransactionMap.containsKey(orderId)) {
          final purchasedItemTransaction = savedUserPurchasedItemTransactionMap[orderId]!;

          if (purchasedItemTransaction is GooglePlayOneTimePurchasedItemTransaction) {
            final oneTimePurchasedItemTransaction = purchasedItemTransaction;

            // add for revocation check later
            updatedPurchasedItemTransactions.add(oneTimePurchasedItemTransaction);
          } else if (purchasedItemTransaction is GooglePlayPurchasedSubscriptionTransaction) {
            final purchasedSubscriptionTransaction = purchasedItemTransaction;
            final updatedApiPurchasedSubscription =
                updatedApiPurchasedItem as GooglePlayApiPurchasedSubscription;

            final updatedPurchasedSubscriptionTransaction =
                _updateGooglePlayPurchasedSubscriptionTransactionFromApiOne(
              purchasedSubscriptionTransaction: purchasedSubscriptionTransaction,
              updatedApiPurchasedSubscription: updatedApiPurchasedSubscription,
            );

            updatedPurchasedItemTransactions.add(updatedPurchasedSubscriptionTransaction);
          }
        } else {
          if (updatedApiPurchasedItem is GooglePlayApiOneTimePurchasedItem) {
            final apiOneTimePurchasedItem = updatedApiPurchasedItem;

            final oneTimePurchasedItemTransaction =
                _createGooglePlayOneTimePurchasedItemTransactionFromApiOne(
              apiOneTimePurchasedItem: apiOneTimePurchasedItem,
              googlePlayUserId: effectiveGooglePlayUserId,
              purchaseToken: purchaseToken,
              purchaseItemSku: purchaseItemSku,
              revocationInfo: null,
            );

            updatedPurchasedItemTransactions.add(oneTimePurchasedItemTransaction);
          } else if (updatedApiPurchasedItem is GooglePlayApiPurchasedSubscription) {
            final apiPurchasedSubscription = updatedApiPurchasedItem;

            final purchasedSubscriptionTransaction =
                _createGooglePlayPurchasedSubscriptionTransactionFromApiOne(
              apiPurchasedSubscription: apiPurchasedSubscription,
              googlePlayUserId: effectiveGooglePlayUserId,
              purchaseToken: purchaseToken,
              purchaseItemSku: purchaseItemSku,
              revocationInfo: null,
            );

            updatedPurchasedItemTransactions.add(purchasedSubscriptionTransaction);
          }
        }
      }

      for (var i = 0; i < updatedPurchasedItemTransactions.length; i++) {
        final updatedPurchasedItemTransaction = updatedPurchasedItemTransactions[i];
        final revokedPurchasedItem =
            revokedPurchasedItemMap[updatedPurchasedItemTransaction.orderId];

        if (revokedPurchasedItem == null) {
          continue;
        }

        if (updatedPurchasedItemTransaction is GooglePlayOneTimePurchasedItemTransaction) {
          final updatedOneTimePurchasedItemTransaction = updatedPurchasedItemTransaction;

          updatedPurchasedItemTransactions[i] =
              _updateGooglePlayOneTimePurchasedItemTransactionFromRevokedPurchasedItem(
            oneTimePurchasedItemTransaction: updatedOneTimePurchasedItemTransaction,
            revokedPurchasedItem: revokedPurchasedItem,
          );
        } else if (updatedPurchasedItemTransaction is GooglePlayPurchasedSubscriptionTransaction) {
          final updatedPurchasedSubscriptionTransaction = updatedPurchasedItemTransaction;

          updatedPurchasedItemTransactions[i] =
              _updateGooglePlayPurchasedSubscriptionTransactionFromRevokedPurchasedItem(
            purchasedSubscriptionTransaction: updatedPurchasedSubscriptionTransaction,
            revokedPurchasedItem: revokedPurchasedItem,
          );
        }
      }

      await Future.wait([
        _googlePlayPurchasedItemInfoRepository.upsertPurchasedItemInfos(
          purchasedItemInfos: updatedPurchasedItemInfos.toBuiltList(),
        ),
        _googlePlayTransactionRepository.upsertTransactions(
          purchasedItemTransactions: updatedPurchasedItemTransactions.toBuiltList(),
        ),
      ]);

      futureResults = await Future.wait([
        _googlePlayPurchasedItemInfoRepository.findUserPurchasedItemInfos(
          googlePlayUserId: effectiveGooglePlayUserId,
        ),
        _googlePlayTransactionRepository.findUserTransactions(
          googlePlayUserId: effectiveGooglePlayUserId,
        ),
      ]);

      i = 0;

      final actualUserPurchasedItemInfos =
          futureResults[i++] as BuiltList<GooglePlayPurchasedItemInfo>;
      final actualUserPurchasedItemTransactions =
          futureResults[i++] as BuiltList<GooglePlayTransaction>;

      apiGooglePlayPurchasedItems = _createApiGooglePlayPurchasedItemsFromInternalOnes(
        purchasedItemInfos: actualUserPurchasedItemInfos,
        purchasedItemTransactions: actualUserPurchasedItemTransactions,
      );
    }

    // change google play user link if needed

    if (userId != null &&
        effectiveGooglePlayUserId != null &&
        effectiveGooglePlayUserId != linkedGooglePlayUserId) {
      final userLink = GooglePlayUserToUserLink(
        userId: userId,
        googlePlayUserId: effectiveGooglePlayUserId,
      );

      await _googlePlayUserToUserLinkRepository.upsertLink(
        link: userLink,
      );
    }

    // change devices to google play user link if needed

    if (effectiveGooglePlayUserId != null && deviceId != null) {
      final link = await _devicesToGooglePlayUserLinkRepository.findLinkByGooglePlayUserId(
        googlePlayUserId: effectiveGooglePlayUserId,
      );

      DevicesToGooglePlayUserLink? updatedLink;

      if (link == null) {
        updatedLink = DevicesToGooglePlayUserLink(
          googlePlayUserId: effectiveGooglePlayUserId,
          deviceIds: BuiltList(<String>[
            deviceId,
          ]),
        );
      } else {
        if (!link.deviceIds.contains(deviceId)) {
          final updatedDeviceIds = link.deviceIds.rebuild((deviceIds) {
            deviceIds.add(deviceId);
          });

          updatedLink = link.copyWith(
            deviceIds: () => updatedDeviceIds,
          );
        }
      }

      if (updatedLink != null) {
        await _devicesToGooglePlayUserLinkRepository.upsertLink(
          link: updatedLink,
        );
      }
    }

    // restore app store purchased items

    String? effectiveAppStoreOriginalTransactionId;
    String? effectiveAppStoreUserId;

    var apiAppStorePurchasedItems = BuiltList<ApiAppStorePurchasedItem>();

    if (appStoreReceipt != null) {
      final failureOrOriginalTransactionId =
          await _appStoreApiPurchasedItemRepository.getOriginalTransactionId(
        receipt: appStoreReceipt,
      );

      if (failureOrOriginalTransactionId.isLeft()) {
        return left(const PurchasedItemRestorationFailure());
      }

      effectiveAppStoreOriginalTransactionId = failureOrOriginalTransactionId.asRight();
    } else if (linkedAppStoreUserId != null) {
      effectiveAppStoreUserId = linkedAppStoreUserId;

      final transactions = await _appStoreTransactionRepository.findUserTransactions(
        appStoreUserId: linkedAppStoreUserId,
      );

      effectiveAppStoreOriginalTransactionId = transactions.first.originalTransactionId;
    }

    if (effectiveAppStoreOriginalTransactionId != null) {
      final futureResults = await Future.wait([
        _appStoreApiPurchasedItemRepository.getTransactionHistory(
          originalTransactionId: effectiveAppStoreOriginalTransactionId,
        ),
        _appStoreApiPurchasedItemRepository.getRenewalInfos(
          originalTransactionId: effectiveAppStoreOriginalTransactionId,
        ),
      ]);

      var i = 0;

      final failureOrTransactionHistory = futureResults[i++]
          as Either<AppStoreApiTransactionHistoryGettingFailure, BuiltList<AppStoreApiTransaction>>;
      final failureOrRenewalInfos = futureResults[i++] as Either<
          AppStoreApiPurchasedSubscriptionRenewalInfoGettingFailure,
          BuiltList<AppStoreApiPurchasedSubscriptionRenewalInfo>>;

      if (failureOrTransactionHistory.isRight() && failureOrRenewalInfos.isRight()) {
        final apiTransactionHistory = failureOrTransactionHistory.asRight();

        if (effectiveAppStoreUserId == null) {
          final apiTransactionIds = apiTransactionHistory.map((transaction) {
            return transaction.id;
          }).toBuiltList();

          final nullableTransactions = await _appStoreTransactionRepository.findTransactionsByIds(
            ids: apiTransactionIds,
          );

          final transactions = nullableTransactions.whereType<AppStoreTransaction>();

          if (transactions.isEmpty) {
            effectiveAppStoreUserId = UuidGenerator().generateUuid();
          } else {
            effectiveAppStoreUserId = transactions.first.appStoreUserId;
          }
        }

        final updatedTransactions = apiTransactionHistory.map((apiTransaction) {
          return _createAppStoreTransactionFromApiOne(
            apiTransaction: apiTransaction,
            appStoreUserId: effectiveAppStoreUserId!,
          );
        }).toBuiltList();

        final apiRenewalInfos = failureOrRenewalInfos.asRight();

        final updatedPurchasedSubscriptionInfos = apiRenewalInfos.map((apiRenewalInfo) {
          return _createAppStorePurchasedSubscriptionInfoFromApiOne(
            apiRenewalInfo: apiRenewalInfo,
            appStoreUserId: effectiveAppStoreUserId!,
          );
        }).toBuiltList();

        await Future.wait([
          _appStoreTransactionRepository.replaceUserTransactions(
            appStoreUserId: effectiveAppStoreUserId,
            transactions: updatedTransactions,
          ),
          _appStorePurchasedSubscriptionInfoRepository.replaceUserPurchasedSubscriptionInfos(
            appStoreUserId: effectiveAppStoreUserId,
            purchasedSubscriptionInfos: updatedPurchasedSubscriptionInfos,
          ),
        ]);

        apiAppStorePurchasedItems = _createApiAppStorePurchasedItemsFromInternalOnes(
          transactions: updatedTransactions,
          purchasedSubscriptionInfos: updatedPurchasedSubscriptionInfos,
        );
      } else {
        var transactions =
            await _appStoreTransactionRepository.findTransactionsByOriginalTransactionId(
          originalTransactionId: effectiveAppStoreOriginalTransactionId,
        );

        if (transactions.isNotEmpty) {
          effectiveAppStoreUserId = transactions.first.appStoreUserId;

          final futureResults = await Future.wait([
            _appStoreTransactionRepository.findUserTransactions(
              appStoreUserId: effectiveAppStoreUserId,
            ),
            _appStorePurchasedSubscriptionInfoRepository.findUserPurchasedSubscriptionInfos(
              appStoreUserId: effectiveAppStoreUserId,
            ),
          ]);

          var i = 0;

          transactions = futureResults[i++] as BuiltList<AppStoreTransaction>;
          final purchasedSubscriptionInfos =
              futureResults[i++] as BuiltList<AppStorePurchasedSubscriptionInfo>;

          apiAppStorePurchasedItems = _createApiAppStorePurchasedItemsFromInternalOnes(
            transactions: transactions,
            purchasedSubscriptionInfos: purchasedSubscriptionInfos,
          );
        }
      }
    }

    // change app store user link if needed

    if (userId != null &&
        effectiveAppStoreUserId != null &&
        effectiveAppStoreUserId != linkedAppStoreUserId) {
      final link = AppStoreUserToUserLink(
        userId: userId,
        appStoreUserId: effectiveAppStoreUserId,
      );

      await _appStoreUserToUserLinkRepository.upsertLink(
        link: link,
      );
    }

    // change devices to app store user link if needed

    if (effectiveAppStoreUserId != null && deviceId != null && deviceId.isNotEmpty) {
      final link = await _devicesToAppStoreUserLinkRepository.findLinkByAppStoreUserId(
        appStoreUserId: effectiveAppStoreUserId,
      );

      DevicesToAppStoreUserLink? updatedLink;

      if (link == null) {
        updatedLink = DevicesToAppStoreUserLink(
          appStoreUserId: effectiveAppStoreUserId,
          deviceIds: BuiltList(<String>[
            deviceId,
          ]),
        );
      } else {
        if (!link.deviceIds.contains(deviceId)) {
          final updatedDeviceIds = link.deviceIds.rebuild((deviceIds) {
            deviceIds.add(deviceId);
          });

          updatedLink = link.copyWith(
            deviceIds: () => updatedDeviceIds,
          );
        }
      }

      if (updatedLink != null) {
        await _devicesToAppStoreUserLinkRepository.upsertLink(
          link: updatedLink,
        );
      }
    }

    // check yookassa pending order statuses

    var apiWebPurchasedItems = BuiltList<ApiWebPurchasedItem>();

    if (userId != null) {
      var futureResults = await Future.wait([
        _yookassaPendingOrderRepository.findUserPendingOrders(
          userId: userId,
        ),
        _webTransactionRepository.findUserTransactions(
          userId: userId,
        ),
        _webPurchaseItemRepository.findAllPurchaseItems(),
      ]);

      var i = 0;
      final pendingOrders = futureResults[i++] as BuiltList<YookassaPendingOrder>;
      final transactions = futureResults[i++] as BuiltList<WebTransaction>;
      final purchaseItems = futureResults[i++] as BuiltList<WebPurchaseItem>;

      final purchaseItemMap = <String, WebPurchaseItem>{};

      for (final purchaseItem in purchaseItems) {
        purchaseItemMap[purchaseItem.sku] = purchaseItem;
      }

      for (final pendingOrder in pendingOrders) {
        final failureOrYookassaApiPayment = await _yookassaApiPaymentRepository.getPayment(
          paymentId: pendingOrder.yookassaApiPendingPaymentId,
        );

        if (failureOrYookassaApiPayment.isLeft()) {
          continue;
        }

        final yookassaApiPayment = failureOrYookassaApiPayment.asRight();

        if (yookassaApiPayment is YookassaApiCanceledPayment) {
          await _yookassaPendingOrderRepository.deletePendingOrderByYookassaPaymentId(
            yookassaPaymentId: pendingOrder.yookassaApiPendingPaymentId,
          );
        } else if (yookassaApiPayment is YookassaApiSucceededPayment) {
          final yookassaApiPaymentMethod = yookassaApiPayment.paymentMethod;
          YookassaPaymentMethod? existingYookassaPaymentMethod;

          if (yookassaApiPayment.savedPaymentMethodId != null) {
            existingYookassaPaymentMethod = await _webPaymentMethodRepository.findPaymentMethod(
              id: yookassaApiPayment.savedPaymentMethodId!,
            ) as YookassaPaymentMethod;
          }

          final YookassaPaymentMethod effectiveYookassaPaymentMethod;

          if (existingYookassaPaymentMethod == null) {
            effectiveYookassaPaymentMethod = _createYookassaPaymentMethodFromApiOne(
              apiPaymentMethod: yookassaApiPaymentMethod,
              userId: yookassaApiPayment.userId,
            );
          } else {
            effectiveYookassaPaymentMethod = _updateYookassaPaymentMethodFromApiOne(
              paymentMethod: existingYookassaPaymentMethod,
              apiPaymentMethod: yookassaApiPaymentMethod,
            );
          }

          late final YookassaTransaction yookassaTransaction;
          WebPurchasedSubscriptionInfo? newPurchasedSubscriptionInfo;

          final purchaseItem = purchaseItemMap[yookassaApiPayment.purchaseItemSku]!;

          if (purchaseItem is WebOneTimePurchaseItem) {
            yookassaTransaction = _createYookassaOneTimePurchasedItemTransactionFromApiOne(
              apiPayment: yookassaApiPayment,
              paymentMethodId: effectiveYookassaPaymentMethod.id,
            );
          } else if (purchaseItem is WebSubscription) {
            final purchasedSubscriptionTransactions =
                transactions.whereType<WebPurchasedSubscriptionTransaction>();

            final previousTransactions = purchasedSubscriptionTransactions.where((transaction) {
              return transaction.purchaseItemSku == yookassaApiPayment.purchaseItemSku &&
                  transaction.test == yookassaApiPayment.test;
            }).toList();

            previousTransactions.sort((first, second) {
              return first.time.compareTo(second.time);
            });

            final expirationTimeMap = _getWebPurchasedSubscriptionTransactionExpirationTimeMap(
              transactions: previousTransactions.toBuiltList(),
              subscriptionDuration: purchaseItem.duration,
              test: yookassaApiPayment.test,
            );

            final previousUnrevokedTransactions = previousTransactions.where((transaction) {
              return !transaction.revoked;
            });

            WebPurchasedSubscriptionTransaction? lastUnrevokedTransaction;
            DateTime? lastUnrevokedTransactionExpirationTime;

            if (previousUnrevokedTransactions.isNotEmpty) {
              lastUnrevokedTransaction = previousUnrevokedTransactions.last;
              lastUnrevokedTransactionExpirationTime =
                  expirationTimeMap[lastUnrevokedTransaction.id]!;
            }

            final currentTime = DateTime.now().toUtc();
            final purchasedSubscriptionMaxLapseDuration =
                _getWebPurchasedSubscriptionMaxLapseDuration(
              test: yookassaApiPayment.test,
            );

            if (lastUnrevokedTransaction == null ||
                currentTime.difference(lastUnrevokedTransactionExpirationTime!) >
                    purchasedSubscriptionMaxLapseDuration) {
              final yookassaPurchasedSubscriptionTransaction =
                  _createYookassaPurchasedSubscriptionTransactionFromApiOne(
                apiPayment: yookassaApiPayment,
                paymentMethodId: effectiveYookassaPaymentMethod.id,
              );

              yookassaTransaction = yookassaPurchasedSubscriptionTransaction;

              newPurchasedSubscriptionInfo = YookassaPurchasedSubscriptionInfo(
                originalTransactionId:
                    yookassaPurchasedSubscriptionTransaction.originalTransactionId,
                userId: yookassaPurchasedSubscriptionTransaction.userId,
                purchaseItemSku: yookassaApiPayment.purchaseItemSku,
                autoRenewalEnabled: true,
                currentRenewalAttemptTimes: BuiltList(),
                test: yookassaPurchasedSubscriptionTransaction.test,
              );
            } else {
              yookassaTransaction = _createYookassaPurchasedSubscriptionTransactionFromApiOne(
                apiPayment: yookassaApiPayment,
                originalTransactionId: lastUnrevokedTransaction.originalTransactionId,
                paymentMethodId: effectiveYookassaPaymentMethod.id,
              );
            }
          }

          await Future.wait([
            _webPaymentMethodRepository.upsertPaymentMethod(
              paymentMethod: effectiveYookassaPaymentMethod,
            ),
            _webTransactionRepository.upsertTransaction(
              transaction: yookassaTransaction,
            ),
            _yookassaPendingOrderRepository.deletePendingOrderByYookassaPaymentId(
              yookassaPaymentId: yookassaApiPayment.id,
            ),
            if (newPurchasedSubscriptionInfo != null)
              _webPurchasedSubscriptionInfoRepository.upsertPurchasedSubscriptionInfo(
                purchasedSubscriptionInfo: newPurchasedSubscriptionInfo,
              ),
          ]);
        }
      }

      futureResults = await Future.wait([
        _webTransactionRepository.findUserTransactions(
          userId: userId,
        ),
        _webPurchasedSubscriptionInfoRepository.findUserPurchasedSubscriptionInfos(
          userId: userId,
        ),
      ]);

      i = 0;
      final updatedTransactions = futureResults[i++] as BuiltList<WebTransaction>;
      final updatedPurchasedSubscriptionInfos =
          futureResults[i++] as BuiltList<WebPurchasedSubscriptionInfo>;

      final updatedYookassaTransactions =
          updatedTransactions.whereType<YookassaTransaction>().toBuiltList();
      final updatedYookassaPurchasedSubscriptionInfos = updatedPurchasedSubscriptionInfos
          .whereType<YookassaPurchasedSubscriptionInfo>()
          .toBuiltList();

      apiWebPurchasedItems = _createApiWebPurchasedItemsFromInternalOnes(
        transactions: updatedYookassaTransactions,
        purchasedSubscriptionInfos: updatedYookassaPurchasedSubscriptionInfos,
        purchaseItemMap: purchaseItemMap.build(),
      );
    }

    final result = PurchasedItemRestorationResult(
      apiAppStorePurchasedItems: apiAppStorePurchasedItems,
      apiGooglePlayPurchasedItems: apiGooglePlayPurchasedItems,
      apiWebPurchasedItems: apiWebPurchasedItems,
    );

    return right(result);
  }
}
